using System;
using System.Collections;
using Sirenix.OdinInspector;
using TMPro;
using UnityEngine;
using UnityEngine.UI;

namespace TMPAnimationLib
{
    public class TMPAnimComp : MonoBehaviour
    {
        public bool PlayOnAwake;
        public AnimConfig Config;
        public TextMeshProUGUI Text;
        [Title("是否使用描边")]
        public bool UseOutline;
        [Title("描边配置"), ShowIf("@this.UseOutline == true")]
        public Vector4 OutlineConfig;
        
        /// <summary>
        /// 单个字符动画的完成事件
        /// </summary>
        public event Action<CharObject> SingleCharAnimCompletedEvent;

        Action<CharObject> mSingleCharAnimCompletedEvent;

        /// <summary>
        /// 所有字符动画完成后的事件
        /// </summary>
        public event Action TotalAnimCompletedEvent;

        Action mTotalAnimCompletedEvent;


        /// <summary>
        /// 文本组件信息
        /// </summary>
        TMP_TextInfo mTextInfo;

        /// <summary>
        /// Mesh顶点数据缓存
        /// </summary>
        Vector3[] mCacheMeshVertices;

        IAnimSchedule mSchedule;
        CharObject[] mCharArray;
        int mCharCount;
        bool mIsValid;


        void Awake()
        {
            Text = GetComponent<TextMeshProUGUI>();
            mTextInfo = Text.textInfo;
            mSchedule = new AnimSchedule();
            mSingleCharAnimCompletedEvent = OnSingleCharAnimCompleted;
            mTotalAnimCompletedEvent = OnTotalAnimCompleted;
            mIsValid = false;
            Text.OnPreRenderText += info =>
            {
                //文本内容改变时调用
                BackupMeshInfoVertexData(0);
                mIsValid = true;
                if (Config.IsHideCharBeforeAnimBegin)
                {
                    mCharArray = null;
                    InitCharArray();
                    foreach (var item in mCharArray)
                        item.Hide();
                }
            };

            if (PlayOnAwake && Application.isPlaying)
            {
                PlayAnim();
            }
        }

        void OnEnable()
        {
            mIsValid = false; //等待文本渲染完成
        }

        void Update()
        {
            mSchedule?.OnUpdate();
        }

        /// <summary>
        /// 播放动画
        /// </summary>
        [Button("播放动画"), GUIColor(0, 1, 0)]
        public void PlayAnimTest()
        {
#if UNITY_EDITOR
            if (!Application.isPlaying)
            {
                Debug.LogError("只可在运行时播放文本动画!");
                return;
            }
#endif
            PlayAnim();
        }

        /// <summary>
        /// 播放动画
        /// </summary>
        public void PlayAnim()
        {
            void Internal_PlayAnim()
            {
                if (!CheckValid("PlayTextAnim error!")) return;
                RecoverMeshInfoVertexData(0);
                InitCharArray();
                AnimSchedule schedule = (AnimSchedule) mSchedule;
                schedule.Init(Config, mCharArray);
                schedule.Reset();
                schedule.SingleCharAnimCompletedEvent += mSingleCharAnimCompletedEvent;
                schedule.TotalAnimCompletedEvent += mTotalAnimCompletedEvent;
                schedule.Start();
                //Debug.Log($"动画播放开始, Time : {Time.time}");
            }
            
            if (mIsValid)
                Internal_PlayAnim();
            else
            {
                IEnumerator PlayAnimCoro()
                {
                    while (!mIsValid)
                        yield return null;
                    Internal_PlayAnim();
                }
            
                StartCoroutine(PlayAnimCoro());
            }
        }

        [Button("Backup"), GUIColor(0, 1, 0)]
        public void Backup()
        {
            BackupMeshInfoVertexData(0);
        }

        [Button("Recover"), GUIColor(0, 1, 0)]
        public void Recover()
        {
            RecoverMeshInfoVertexData(0);
        }

        /// <summary>
        /// 备份Mesh顶点数据
        /// 文本改变时会自动调用一次
        /// </summary>
        public void BackupMeshInfoVertexData(int matIndex)
        {
            var vertices = mTextInfo?.meshInfo[matIndex].vertices;
            if (vertices != null)
            {
                if (mCacheMeshVertices == null || mCacheMeshVertices.Length != vertices.Length)
                    mCacheMeshVertices = new Vector3[vertices.Length];
                for (int i = 0; i < vertices.Length; i++)
                    mCacheMeshVertices[i] = vertices[i];
            }
        }

        /// <summary>
        /// 恢复Mesh顶点数据
        /// 播放动画时会自动调用一次
        /// </summary>
        public void RecoverMeshInfoVertexData(int matIndex)
        {
            if (mTextInfo != null && mCacheMeshVertices != null)
            {
                var vertices = mTextInfo.meshInfo[matIndex].vertices;
                for (int i = 0; i < mCacheMeshVertices.Length; i++)
                    vertices[i] = mCacheMeshVertices[i];
                mTextInfo.meshInfo[matIndex].mesh.vertices = vertices;
                Text.UpdateGeometry(mTextInfo.meshInfo[matIndex].mesh, matIndex);
            }
        }

        /// <summary>
        /// 检测 TMP 组件是否合法
        /// </summary>
        bool CheckValid(string errorMsg)
        {
            if (Text == null)
            {
                Debug.LogError($"{errorMsg} 不存在 TextMeshProUGUI 组件!");
                return false;
            }

            if (mTextInfo.characterCount == 0)
            {
                Debug.LogWarning($"{errorMsg} 字符数量为 0!");
                return false;
            }

            return true;
        }

        /// <summary>
        /// 初始化字符数组
        /// </summary>
        void InitCharArray()
        {
            mCharCount = mTextInfo.characterCount;
            if (mCharArray == null || mCharArray.Length != mCharCount)
                mCharArray = new CharObject[mCharCount];
            int extraVertexCount = CalculateExtraVertexCount(UseOutline, OutlineConfig);
            for (int i = 0; i < mCharCount; i++)
            {
                CharObject obj = new CharObject();
                obj.SetData(Text, i, Config, extraVertexCount);
                mCharArray[i] = obj;
            }
        }

        int CalculateExtraVertexCount(bool useOutline, Vector4 outlineConfig)
        {
            if (!useOutline) return 0;
            int maxOffset = Int32.MinValue;
            int minOffset = Int32.MaxValue;
            for (int i = 0; i < 4; i++)
            {
                int axisOffset = (int)outlineConfig[i];
                maxOffset = Mathf.Max(maxOffset, axisOffset);
                minOffset = Mathf.Min(minOffset, axisOffset);
            }
            int MODIFY_OUTLINE_SMOOTH = maxOffset - minOffset + 1;
            int extraVertexCount = MODIFY_OUTLINE_SMOOTH * 4 + 4;
            return extraVertexCount;
        }

        void OnTotalAnimCompleted()
        {
            TotalAnimCompletedEvent?.Invoke();
            TotalAnimCompletedEvent = null;
            SingleCharAnimCompletedEvent = null;
            //Debug.Log($"动画播放完成, Time : {Time.time}");
        }

        void OnSingleCharAnimCompleted(CharObject obj)
        {
            SingleCharAnimCompletedEvent?.Invoke(obj);
        }
    }
}